import { unique } from "./unique"

// 差 - 去重
// const result = difference([1, 2, 3, 4, 5, 6, 6, 7, 7], [3, 4, 5], [1, 7], 3, 11) => [2,6]
export function difference(X: any, ...arrays: any[]): any[]
export function difference(X: any[], ...arrays: any[]): any[] {
  if (X == null || !Array.isArray(X) || X.length == 0) return []
  if (arrays.length === 0) return X
  let result = unique(X)
  for (let i = 0; i < arrays.length; i++) {
    let array: any = arrays[i]
    if (array == null) continue
    if (!Array.isArray(array)) array = [array]
    result = result.filter(element => array.indexOf(element) === -1)
  }

  return result
}

/**
 * 对 X，Y使用 mapFn 映射后的值进行求交
 *
 * **Note:** Unlike `pullAllBy`, this method returns a new array.
 *
 * @param {Array} array The array to inspect.
 * @param {...Array} [values] The values to exclude.
 * @param {Function} [mapFn] The mapFn invoked per element.
 * @returns {Array} Returns the new array of filtered values.
 * @see difference, differenceBy
 * @example
 *
 * differenceBy([3.1, 2.2, 1.3], [4.4, 2.5], Math.floor);
 * // => [3.1, 1.3]
 *
 * differenceBy([{ 'a': 2 }, { 'a': 1 }], [{ 'a': 1 }], x => x.a);
 * // => [{ 'a': 2 }]
 */
export function differenceBy(X: any[], Y: any[], mapFn: (element: any) => any): any[] {
  if (X == null || X.length == 0) return []
  const result = []
  const xMap = X.map(mapFn)
  const yMap = Y.map(mapFn)
  for (let i = 0; i < xMap.length; i++) {
    if (yMap.includes(xMap[i])) {
      result.push(X[i])
    }
  }

  return result
}

/**
 * 对 X，Y使用 isEqual 判定是否相等
 * @param X
 * @param Y
 * @param isEqual
 *
 * const array = [{ 'a': 1, 'b': 2 }, { 'a': 2, 'b': 1 }];
 *
 * differenceWith(array, [{ 'a': 1, 'b': 2 }], (x,y) => x.a == y.a && x.b == y.b);
 * // => [{ 'a': 2, 'b': 1 }]
 */
export function differenceWith(X: any[], Y: any[], isEqual: (x: any, y: any) => boolean): any[] {
  if (X == null || X.length == 0) return []
  const result = []
  for (let i = 0; i < X.length; i++) {
    const x = X[i]
    if (Y.find(y => isEqual(x, y)) != null) {
      result.push(X[i])
    }
  }

  return result
}
